﻿using CServiceStack.Interface;
using CServiceStack.Net30.Collections.Concurrent;
using CServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SomeServices
{
    public class RequestCounter
    {
        private int _counter = 0;
        public int Counter
        {
            get { return _counter; }
        }
        public int INCR()//(Type requestType)
        {
            //int key = requestType.GetHashCode();
            //if (_dictCounter.ContainsKey(key))
            //{
            //    Interlocked.Add(ref _dictCounter[key], 1);
            //}
            Interlocked.Add(ref _counter, 1);
            Debug.WriteLine(_counter);
            return _counter;
        }

        public int DECR()//(Type requestType)
        {
            Interlocked.Add(ref _counter, -1);
            return _counter;
        }
    }
    public static class RequestCounterCollection
    {
        public static ConcurrentDictionary<string, RequestCounter> _dictCounter = new ConcurrentDictionary<string, RequestCounter>();
        public static bool TryAddCounter(string counterName)
        {
            return _dictCounter.TryAdd(counterName, new RequestCounter());
        }
        //private static ConcurrentDictionary<int, int> _dictCounter = new ConcurrentDictionary<int, int>();
        //private static ConcurrentDictionary<string, int> _counterDict;
        public static int INCR(string counterName)
        {
            return _dictCounter[counterName].INCR();
        }
        public static int DECR(string counterName)
        {
            return _dictCounter[counterName].DECR();
        }

        public static int GetCounter(string counterName)
        {
            return _dictCounter[counterName].Counter;
        }
    }

    public class ThrottlingRequestFilter : RequestFilterAttribute
    {

        public ThrottlingRequestFilter(string counterName, int threshold)
        {
            CounterName = counterName;
            Threshold = threshold;
            RequestCounterCollection.TryAddCounter(CounterName);
        }
        public string CounterName { get; set; }
        public int Threshold { get; set; }
        public override void Execute(CServiceStack.ServiceHost.IHttpRequest req, CServiceStack.ServiceHost.IHttpResponse res, object requestDto)
        {
            if (RequestCounterCollection.GetCounter(CounterName) >= Threshold)
            {
                res.StatusCode = 439;
                res.StatusDescription = string.Format("rate limiting due to request throttling threshold {0}", Threshold);
                res.End();
            }
            Task.Factory.StartNew(() => RequestCounterCollection.INCR(CounterName));
        }
    }

    public class ThrottlingResponseFilter : Attribute, IHasResponseFilter
    {
        public string CounterName { get; set; }

        public ThrottlingResponseFilter(string counterName)
        {
            CounterName = counterName;
        }
        public IHasResponseFilter Copy()
        {
            return this;
        }

        public int Priority
        {
            get { return -1; }
        }

        public void ResponseFilter(IHttpRequest req, IHttpResponse res, object response)
        {
            Task.Factory.StartNew(() => RequestCounterCollection.DECR(CounterName));
        }
    }
}
